package eu.briano.suirvellancecamera;

import android.graphics.Bitmap;
import android.graphics.Color;


public class ImageProcessing {



	private int[][][] backgroundYUV;
	private int[][]   backgroundNoiseYUV;



	public void calculateBckYUV(int w, int h, int [][][] inputImage) {
		if (inputImage == null)
			return;
		if (backgroundYUV == null ) {
			backgroundYUV =  new int[Utils.ipSize][Utils.ipSize][3];
			for (int x = 0 ;  x < w; x++)
				for (int y = 0 ;  y < h; y++) {
					for (int i = 0 ; i < 3 ; i++)
					backgroundYUV[x][y][i] = inputImage[x][y][i]*Utils.fixedPrecision;
				}			
		} else {
			int yuv[] =  null;
			float rM = 0;
			for (int x = 0 ;  x < w; x++)
				for (int y = 0 ;  y < h; y++) {
					for (int i = 0 ; i < 3 ; i++) {
					yuv = inputImage[x][y];
					int sG = yuv[i]*Utils.fixedPrecision;
					int bG = backgroundYUV[x][y][i];
					int r =  (int) (( (Utils.bgCalcIteration-1) *bG + sG ) /Utils.bgCalcIteration);
					backgroundYUV[x][y][i] = r;
					rM = rM+r /(Utils.ipSizeArea);
					}
				}
			Log.v(Utils.logName,"pixel mean is "+(rM/Utils.fixedPrecision)/3);
		}

	}

	public void diffBackGroundYUV(int w, int h ,int [][][] inputImage, int[][][] a) {
		if (a == null) 
			return;

		double rM = 0;
		for (int x = 0 ;  x < w; x++)
			for (int y = 0 ;  y < h; y++) {
				
				int yuv[] = inputImage[x][y];
				int aG = yuv[Utils.yuvChannel] * Utils.fixedPrecision;
				int bG = backgroundYUV[x][y][Utils.yuvChannel];
				int  r = (aG-bG);
				if (r<0) r= -r;
				int c  = 0;
				rM = rM+r /(Utils.ipSizeArea);
				if (r > Utils.pixelNoisePct*Utils.yuvScale[Utils.yuvChannel]* Utils.fixedPrecision ) c=255;
				
				
				a[x][y][0] = c;
				a[x][y][1] = c;
				a[x][y][2] = c;

			}
		Log.v(Utils.logName,"diff  mean is "+(rM/ Utils.fixedPrecision));

	}

	public float pow(int[][][] a) {
		if (a == null ) 
			return 0;
		int h = Utils.ipSize;
		int w = h;
		int area =255 * h*w;
		float changed = 0;
		for (int x = 0 ;  x < w; x++)
			for (int y = 0 ;  y < h; y++) {
				float aG = green(a[x][y]);
				aG = aG/area;
				changed = changed + aG;
			}
		return changed;
	}	

	public int bound256(int r) {
		if (r < 0 )
			return 0;
		if (r > 255)
			return 255;
		return r;
	}

	public void removeSparkle(int w, int h, int[][][] inputImage) {
		if (inputImage == null)
			return;
		{
			int[][][] inputImageCopy = new int [w][h][3];
			for (int x = 0 ;  x < w; x++)
				for (int y = 0 ;  y < h; y++) {
					for (int i = 0 ; i < 3; i++)
						inputImageCopy[x][y][i] = inputImage[x][y][i];

				}



			for (int x = 0 ;  x < w; x++)
				for (int y = 0 ;  y < h; y++) {
					int xM1 = x-1;
					int yM1 = y-1;
					int xP1 = x+1;
					int yP1 = y+1;
					xM1 =(xM1< 0)?0:xM1;
					yM1 =(yM1< 0)?0:yM1;
					xP1 =(xP1> h-1)?0:xP1;
					yP1 =(yP1> h-1)?0:yP1;

					int scale = (int) Utils.yuvScale[Utils.yuvChannel];
					int a1 = green(getPixel(inputImageCopy,xM1, yM1))/scale;
					int a2 = green(getPixel(inputImageCopy,xM1, y))/scale;
					int a3 = green(getPixel(inputImageCopy,xM1, yP1))/scale;

					int a4 = green(getPixel(inputImageCopy,xP1, yM1))/scale;
					int a5 = green(getPixel(inputImageCopy,xP1, y))/scale;
					int a6 = green(getPixel(inputImageCopy,xP1, yP1))/scale;

					int a7 = green(getPixel(inputImageCopy,x, yM1))/scale;
					int a8 = green(getPixel(inputImageCopy,x, yP1))/scale;

					int k = green(getPixel(inputImageCopy,x, y))/scale;

					int total = a1+a2+a3+a4+a5+a6+a7+a8;
					if (total < 4 && k > 0  ) { 
						inputImage[x][y][0] = 0;
						inputImage[x][y][1] = 0;
						inputImage[x][y][2] = 255;
					} /*
						else
						if (total >= 3 && k == 0  ) { 
							inputImage[x][y][0] = 255;
							inputImage[x][y][1] = 255;
							inputImage[x][y][2] = 255;
						}
					  */
				}
		}		

	}	
	public int[] getPixel(int[][][] inputImage, int x, int y) {
		return inputImage[x][y];
	}

	public int green(int[] inputImage) {
		return inputImage[1];
	}

	public void calculateNoiseMoving(int w, int h, int[][][] inputImage) {
		if (inputImage == null)
			return;
		if (backgroundNoiseYUV == null ||
				backgroundNoiseYUV.length != w || backgroundNoiseYUV.length == 0 ||
				backgroundNoiseYUV[0].length != h) {
			backgroundNoiseYUV =  new int[w][h];
		} else {
			for (int x = 0 ;  x < w; x++)
				for (int y = 0 ;  y < h; y++) {
					int sG = green(inputImage[x][y])* Utils.fixedPrecision;
					int bG = backgroundNoiseYUV[x][y];
					int res = (int) (( (Utils.bgSnoozeCalcIteration-1) *bG + sG ) /Utils.bgSnoozeCalcIteration)   ;
					backgroundNoiseYUV[x][y] = res;
				}
		}
	
	}

	public void snoozeNoiseZone(int w, int h, int[][][] inputImage) {
		if (inputImage == null || backgroundNoiseYUV == null)
			return;
		{
			for (int x = 0 ;  x < w; x++)
				for (int y = 0 ;  y < h; y++) {
					if (backgroundNoiseYUV[x][y] >  255* Utils.noiseThreshold* Utils.fixedPrecision) {
						inputImage[x][y][0] = 255;
						inputImage[x][y][1] = 0;
						inputImage[x][y][2] = 0;
					}
				}
		}
	}

	public void writeArrayToBitMap(int[][][] src, Bitmap dest) {
		long st = Utils.now();
		for (int x = 0 ;  x < Utils.ipSize; x++)
			for (int y = 0 ;  y <  Utils.ipSize ; y++) {
				dest.setPixel(x, y, Color.rgb(src[x][y][0], src[x][y][1], src[x][y][2]));
			}
		Log.v(Utils.logName," writeArrayToBitMap done in "+(Utils.now() - st));
	}

	public void writeBitMapYUVToArrayF(int [][][] src,int[][][] image) {
		for (int x = 0 ;  x < Utils.ipSize; x++)
			for (int y = 0 ;  y <  Utils.ipSize ; y++) {
				image[x][y][0] =  src[x][y][0];
				image[x][y][1] =  src[x][y][1];
				image[x][y][2] =  src[x][y][2];
			}
	}		

	//http://stackoverflow.com/questions/12469730/confusion-on-yuv-nv21-conversion-to-rgb
	
	public void resizeYUV(int w , int h,byte [] callbackBuffer, int[][][] smallImage){
		long zs = Utils.now();
		int wR = w/Utils.ipSize;
		int hR = h/Utils.ipSize;
		int it = 0;
		long maxY = Long.MIN_VALUE;
		long minY = Long.MAX_VALUE;
		for (int y= 0; y < Utils.ipSize; y++) {
			for (int x= 0; x < Utils.ipSize; x++) {
				long acc = 0;
				for(int yG = y*hR ; yG < (y+1)*hR  ; yG++)
					for(int xG = x*wR ; xG < (x+1)*wR  ; xG++) {
						//YES IT IS NOT A BYTE....
						int Y =  (0xff & ((int) callbackBuffer[xG+yG*w]));
						acc = acc + (Y);
						it++;
					}
				acc = acc/(wR*hR);
				if (acc < minY) minY= acc;
				if (acc > maxY) maxY= acc;
				smallImage[x][y][0] = (int) acc;
			}
		}
		hR=hR/2;
		wR=wR/2;

		long maxU = Long.MIN_VALUE;
		long minU = Long.MAX_VALUE;		

		long maxV = Long.MIN_VALUE;
		long minV = Long.MAX_VALUE;		
		
		
		int uvStart = w*h ;
		for (int y= 0; y < Utils.ipSize; y++) {
			for (int x= 0; x < Utils.ipSize; x++) {
				long accU = 0;
				long accV = 0;
				for(int yG = y*hR ; yG < (y+1)*hR  ; yG++)
					for(int xG = x*wR ; xG < (x+1)*wR  ; xG++) {
						int U =  (0xff & ((int)callbackBuffer[uvStart + xG *2 +yG*w]));
						int V =  (0xff & ((int)callbackBuffer[uvStart + xG *2 +yG*w+1]));
						accU = accU + (U);
						accV = accV + (V);
						it++;
					}
				
				accU= accU/(wR*hR);
				accV= accV/(wR*hR);	
				if (minU > accU) minU = accU; 
				if (minV > accV) minV = accV;

				if (accU > maxU) maxU= accU;
				if (accV > maxV) maxV= accV;
				
				smallImage[x][y][1] = (int) accU;  //BLUE
				smallImage[x][y][2] = (int) accV; //RED
				
			}
		}
		Log.v(Utils.logName, "resized in  "+(Utils.now()-zs) + " from "+w+"x"+h+" to "+Utils.ipSize+"x"+Utils.ipSize+ " iteration:"+it
				+ " Y minValue :" + minY +  " maxValue:"+maxY
				+ " U minValue :" + minU +  " maxValue:"+maxU
				+ " V minValue :" + minV +  " maxValue:"+maxU);
	}
	

}


